﻿using IWMAG.Core.EnhancedProperties.PropertyNodes;
using System.Diagnostics.Contracts;
using System;
using IWMAG.Core.EnhancedProperties.Extensions;

namespace IWMAG.Core.EnhancedProperties
{
    public static class DefaultPropertyExtensions
    {
        public const int DEFAULT_SETVALUE_PRIORITY = 0;
        public static T GetValue<T>(this IPropertyContainer container, PropertyBacker<T> backer)
        {
            Contract.Requires(container != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.IsReadable)
            {
                throw new NotSupportedException("Property does not support gets.");
            }

            if (backer.BackingDictionary.ContainsKey(container.UniqueID))
            {
                return backer.CoerceValueCallback(backer.BackingDictionary[container.UniqueID].GetValue());
            }
            else
            {
                return backer.CoerceValueCallback(backer.DefaultValue.GetNodeValue());
            }
        }

        public static bool GetValue<T>(this TryPropertyBacker tryBacker, PropertyBacker<T> backer, ref T val)
        {
            Contract.Requires(tryBacker != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.IsReadable)
            {
                return false;
            }

            if (backer.BackingDictionary.ContainsKey(tryBacker.Container.UniqueID))
            {
                val =  backer.CoerceValueCallback(backer.BackingDictionary[tryBacker.Container.UniqueID].GetValue());
            }
            else
            {
                val =  backer.CoerceValueCallback(backer.DefaultValue.GetNodeValue());
            }
            return true;
        }
        
        public static void SetConstantValue<T>(this IPropertyContainer owner, PropertyBacker<T> backer, T val, int priority = DEFAULT_SETVALUE_PRIORITY)
        {
            Contract.Requires(owner != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.CanSetValue)
            {
                throw new NotSupportedException("Property does not support sets.");
            }

            var actual = backer.GetOrCreatePropertyNodeList(owner);
            actual.AddOrModifyListMember(priority, i => new SetNode<T>(i, val), node =>
                {
                    node.SetNodeValue(val);
                    return true;
                });

            PropertyManager.RegisterPropertyAffected(owner.UniqueID, backer.UniqueID);
        }

        public static bool SetConstantValue<T>(this TryPropertyBacker owner, PropertyBacker<T> backer, T val, int priority = DEFAULT_SETVALUE_PRIORITY)
        {
            Contract.Requires(owner != null);
            Contract.Requires(backer != null);

            if (!backer.Metadata.CanSetValue)
            {
                return false;
            }

            var actual = backer.GetOrCreatePropertyNodeList(owner.Container);
            actual.AddOrModifyListMember(priority, i => new SetNode<T>(i, val), node =>
            {
                node.SetNodeValue(val);
                return true;
            });

            PropertyManager.RegisterPropertyAffected(owner.Container.UniqueID, backer.UniqueID);
            return true;
        }
      

    }
}
